home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / extlinux.asm < prev    next >
Encoding:
Assembly Source File  |  2005-01-04  |  35.4 KB  |  1,455 lines

  1. ; -*- fundamental -*- (asm-mode sucks)
  2. ; $Id: extlinux.asm,v 1.19 2005/01/04 22:17:17 hpa Exp $
  3. ; ****************************************************************************
  4. ;
  5. ;  extlinux.asm
  6. ;
  7. ;  A program to boot Linux kernels off an ext2/ext3 filesystem.
  8. ;
  9. ;   Copyright (C) 1994-2005  H. Peter Anvin
  10. ;
  11. ;  This program is free software; you can redistribute it and/or modify
  12. ;  it under the terms of the GNU General Public License as published by
  13. ;  the Free Software Foundation, Inc., 53 Temple Place Ste 330,
  14. ;  Boston MA 02111-1307, USA; either version 2 of the License, or
  15. ;  (at your option) any later version; incorporated herein by reference.
  16. ; ****************************************************************************
  17.  
  18. %define IS_EXTLINUX 1
  19. %include "macros.inc"
  20. %include "config.inc"
  21. %include "kernel.inc"
  22. %include "bios.inc"
  23. %include "tracers.inc"
  24. %include "layout.inc"
  25.  
  26. %include "ext2_fs.inc"
  27.  
  28. ;
  29. ; Some semi-configurable constants... change on your own risk.
  30. ;
  31. my_id        equ extlinux_id
  32. ; NASM 0.98.38 croaks if these are equ's rather than macros...
  33. FILENAME_MAX_LG2 equ 8            ; log2(Max filename size Including final null)
  34. FILENAME_MAX    equ (1 << FILENAME_MAX_LG2)    ; Max mangled filename size
  35. NULLFILE    equ 0            ; Null character == empty filename
  36. NULLOFFSET    equ 0            ; Position in which to look
  37. retry_count    equ 6            ; How patient are we with the disk?
  38. %assign HIGHMEM_SLOP 0            ; Avoid this much memory near the top
  39. LDLINUX_MAGIC    equ 0x3eb202fe        ; A random number to identify ourselves with
  40.  
  41. MAX_OPEN_LG2    equ 6            ; log2(Max number of open files)
  42. MAX_OPEN    equ (1 << MAX_OPEN_LG2)
  43.  
  44. SECTOR_SHIFT    equ 9
  45. SECTOR_SIZE    equ (1 << SECTOR_SHIFT)
  46.  
  47. ;
  48. ; This is what we need to do when idle
  49. ;
  50. %macro    RESET_IDLE 0
  51.     ; Nothing
  52. %endmacro
  53. %macro    DO_IDLE 0
  54.     ; Nothing
  55. %endmacro
  56.  
  57. ;
  58. ; The following structure is used for "virtual kernels"; i.e. LILO-style
  59. ; option labels.  The options we permit here are `kernel' and `append
  60. ; Since there is no room in the bottom 64K for all of these, we
  61. ; stick them at vk_seg:0000 and copy them down before we need them.
  62. ;
  63.         struc vkernel
  64. vk_vname:    resb FILENAME_MAX    ; Virtual name **MUST BE FIRST!**
  65. vk_rname:    resb FILENAME_MAX    ; Real name
  66. vk_appendlen:    resw 1
  67.         alignb 4
  68. vk_append:    resb max_cmd_len+1    ; Command line
  69.         alignb 4
  70. vk_end:        equ $            ; Should be <= vk_size
  71.         endstruc
  72.  
  73. ;
  74. ; Segment assignments in the bottom 640K
  75. ; Stick to the low 512K in case we're using something like M-systems flash
  76. ; which load a driver into low RAM (evil!!)
  77. ;
  78. ; 0000h - main code/data segment (and BIOS segment)
  79. ;
  80. real_mode_seg    equ 4000h
  81. cache_seg    equ 3000h        ; 64K area for metadata cache
  82. vk_seg          equ 2000h        ; Virtual kernels
  83. xfer_buf_seg    equ 1000h        ; Bounce buffer for I/O to high mem
  84. comboot_seg    equ real_mode_seg    ; COMBOOT image loading zone
  85.  
  86. ;
  87. ; File structure.  This holds the information for each currently open file.
  88. ;
  89.         struc open_file_t
  90. file_left    resd 1            ; Number of sectors left (0 = free)
  91. file_sector    resd 1            ; Next linear sector to read
  92. file_in_sec    resd 1            ; Sector where inode lives
  93. file_in_off    resw 1
  94. file_mode    resw 1
  95.         endstruc
  96.  
  97. %ifndef DEPEND
  98. %if (open_file_t_size & (open_file_t_size-1))
  99. %error "open_file_t is not a power of 2"
  100. %endif
  101. %endif
  102.  
  103. ; ---------------------------------------------------------------------------
  104. ;   BEGIN CODE
  105. ; ---------------------------------------------------------------------------
  106.  
  107. ;
  108. ; Memory below this point is reserved for the BIOS and the MBR
  109. ;
  110.         section .earlybss
  111. trackbufsize    equ 8192
  112. trackbuf    resb trackbufsize    ; Track buffer goes here
  113. getcbuf        resb trackbufsize
  114.         ; ends at 4800h
  115.  
  116.         section .bss
  117. SuperBlock    resb 1024        ; ext2 superblock
  118. SuperInfo    resq 16            ; DOS superblock expanded
  119. ClustSize    resd 1            ; Bytes/cluster ("block")
  120. SecPerClust    resd 1            ; Sectors/cluster
  121. ClustMask    resd 1            ; Sectors/cluster - 1
  122. PtrsPerBlock1    resd 1            ; Pointers/cluster
  123. PtrsPerBlock2    resd 1            ; (Pointers/cluster)^2
  124. DriveNumber    resb 1            ; BIOS drive number
  125. ClustShift    resb 1            ; Shift count for sectors/cluster
  126. ClustByteShift    resb 1            ; Shift count for bytes/cluster
  127.  
  128.         alignb open_file_t_size
  129. Files        resb MAX_OPEN*open_file_t_size
  130.  
  131. ;
  132. ; Constants for the xfer_buf_seg
  133. ;
  134. ; The xfer_buf_seg is also used to store message file buffers.  We
  135. ; need two trackbuffers (text and graphics), plus a work buffer
  136. ; for the graphics decompressor.
  137. ;
  138. xbs_textbuf    equ 0            ; Also hard-coded, do not change
  139. xbs_vgabuf    equ trackbufsize
  140. xbs_vgatmpbuf    equ 2*trackbufsize
  141.  
  142.  
  143.         section .text
  144. ;
  145. ; Some of the things that have to be saved very early are saved
  146. ; "close" to the initial stack pointer offset, in order to
  147. ; reduce the code size...
  148. ;
  149. StackBuf    equ $-44-32        ; Start the stack here (grow down - 4K)
  150. PartInfo    equ StackBuf        ; Saved partition table entry
  151. FloppyTable    equ PartInfo+16        ; Floppy info table (must follow PartInfo)
  152. OrigFDCTabPtr    equ StackBuf-4        ; The high dword on the stack
  153.  
  154. ;
  155. ; Primary entry point.  Tempting as though it may be, we can't put the
  156. ; initial "cli" here; the jmp opcode in the first byte is part of the
  157. ; "magic number" (using the term very loosely) for the DOS superblock.
  158. ;
  159. bootsec        equ $
  160.         jmp short start        ; 2 bytes
  161.         nop            ; 1 byte
  162. ;
  163. ; "Superblock" follows -- it's in the boot sector, so it's already
  164. ; loaded and ready for us
  165. ;
  166. bsOemName    db 'EXTLINUX'        ; The SYS command sets this, so...
  167. ;
  168. ; These are the fields we actually care about.  We end up expanding them
  169. ; all to dword size early in the code, so generate labels for both
  170. ; the expanded and unexpanded versions.
  171. ;
  172. %macro        superb 1
  173. bx %+ %1    equ SuperInfo+($-superblock)*8+4
  174. bs %+ %1    equ $
  175.         zb 1
  176. %endmacro
  177. %macro        superw 1
  178. bx %+ %1    equ SuperInfo+($-superblock)*8
  179. bs %+ %1    equ $
  180.         zw 1
  181. %endmacro
  182. %macro        superd 1
  183. bx %+ %1    equ $            ; no expansion for dwords
  184. bs %+ %1    equ $
  185.         zd 1
  186. %endmacro
  187. superblock    equ $
  188.         superw BytesPerSec
  189.         superb SecPerClust
  190.         superw ResSectors
  191.         superb FATs
  192.         superw RootDirEnts
  193.         superw Sectors
  194.         superb Media
  195.         superw FATsecs
  196.         superw SecPerTrack
  197.         superw Heads
  198. superinfo_size    equ ($-superblock)-1    ; How much to expand
  199.         superd Hidden
  200.         superd HugeSectors
  201.         ;
  202.         ; This is as far as FAT12/16 and FAT32 are consistent
  203.         ;
  204.         zb 54            ; FAT12/16 need 26 more bytes,
  205.                     ; FAT32 need 54 more bytes
  206. superblock_len    equ $-superblock
  207.  
  208. ;
  209. ; Note we don't check the constraints above now; we did that at install
  210. ; time (we hope!)
  211. ;
  212. start:
  213.         cli            ; No interrupts yet, please
  214.         cld            ; Copy upwards
  215. ;
  216. ; Set up the stack
  217. ;
  218.         xor ax,ax
  219.         mov ss,ax
  220.         mov sp,StackBuf        ; Just below BSS
  221.         mov es,ax
  222. ;
  223. ; DS:SI may contain a partition table entry.  Preserve it for us.
  224. ;
  225.         mov cx,8        ; Save partition info
  226.         mov di,sp
  227.         rep movsw
  228.  
  229.         mov ds,ax        ; Now we can initialize DS...
  230.  
  231. ;
  232. ; Now sautee the BIOS floppy info block to that it will support decent-
  233. ; size transfers; the floppy block is 11 bytes and is stored in the
  234. ; INT 1Eh vector (brilliant waste of resources, eh?)
  235. ;
  236. ; Of course, if BIOSes had been properly programmed, we wouldn't have
  237. ; had to waste precious space with this code.
  238. ;
  239.         mov bx,fdctab
  240.         lfs si,[bx]        ; FS:SI -> original fdctab
  241.         push fs            ; Save on stack in case we need to bail
  242.         push si
  243.  
  244.         ; Save the old fdctab even if hard disk so the stack layout
  245.         ; is the same.  The instructions above do not change the flags
  246.         mov [DriveNumber],dl    ; Save drive number in DL
  247.         and dl,dl        ; If floppy disk (00-7F), assume no
  248.                     ; partition table
  249.         js harddisk
  250.  
  251. floppy:
  252.         mov cl,6        ; 12 bytes (CX == 0)
  253.         ; es:di -> FloppyTable already
  254.         ; This should be safe to do now, interrupts are off...
  255.         mov [bx],di        ; FloppyTable
  256.         mov [bx+2],ax        ; Segment 0
  257.         fs rep movsw        ; Faster to move words
  258.         mov cl,[bsSecPerTrack]  ; Patch the sector count
  259.         mov [di-8],cl
  260.         ; AX == 0 here
  261.         int 13h            ; Some BIOSes need this
  262.  
  263.         jmp short not_harddisk
  264. ;
  265. ; The drive number and possibly partition information was passed to us
  266. ; by the BIOS or previous boot loader (MBR).  Current "best practice" is to
  267. ; trust that rather than what the superblock contains.
  268. ;
  269. ; Would it be better to zero out bsHidden if we don't have a partition table?
  270. ;
  271. ; Note: di points to beyond the end of PartInfo
  272. ;
  273. harddisk:
  274.         test byte [di-16],7Fh    ; Sanity check: "active flag" should
  275.         jnz no_partition    ; be 00 or 80
  276.         mov eax,[di-8]        ; Partition offset (dword)
  277.         mov [bsHidden],eax
  278. no_partition:
  279. ;
  280. ; Get disk drive parameters (don't trust the superblock.)  Don't do this for
  281. ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
  282. ; what the *drive* supports, not about the *media*.  Fortunately floppy disks
  283. ; tend to have a fixed, well-defined geometry which is stored in the superblock.
  284. ;
  285.         ; DL == drive # still
  286.         mov ah,08h
  287.         int 13h
  288.         jc no_driveparm
  289.         and ah,ah
  290.         jnz no_driveparm
  291.         shr dx,8
  292.         inc dx            ; Contains # of heads - 1
  293.         mov [bsHeads],dx
  294.         and cx,3fh
  295.         mov [bsSecPerTrack],cx
  296. no_driveparm:
  297. not_harddisk:
  298. ;
  299. ; Ready to enable interrupts, captain
  300. ;
  301.         sti
  302.  
  303.  
  304. ;
  305. ; Do we have EBIOS (EDD)?
  306. ;
  307. eddcheck:
  308.         mov bx,55AAh
  309.         mov ah,41h        ; EDD existence query
  310.         mov dl,[DriveNumber]
  311.         int 13h
  312.         jc .noedd
  313.         cmp bx,0AA55h
  314.         jne .noedd
  315.         test cl,1        ; Extended disk access functionality set
  316.         jz .noedd
  317.         ;
  318.         ; We have EDD support...
  319.         ;
  320.         mov byte [getlinsec.jmp+1],getlinsec_ebios-(getlinsec.jmp+2)
  321. .noedd:
  322.  
  323. ;
  324. ; Load the first sector of LDLINUX.SYS; this used to be all proper
  325. ; with parsing the superblock and root directory; it doesn't fit
  326. ; together with EBIOS support, unfortunately.
  327. ;
  328.         mov eax,[FirstSector]    ; Sector start
  329.         mov bx,ldlinux_sys    ; Where to load it
  330.         call getonesec
  331.         
  332.         ; Some modicum of integrity checking
  333.         cmp dword [ldlinux_magic],LDLINUX_MAGIC
  334.         jne kaboom
  335.         cmp dword [ldlinux_magic+4],HEXDATE
  336.         jne kaboom
  337.  
  338.         ; Go for it...
  339.         jmp ldlinux_ent
  340.  
  341. ;
  342. ; kaboom: write a message and bail out.
  343. ;
  344. kaboom:
  345.         xor si,si
  346.         mov ss,si        
  347.         mov sp,StackBuf-4     ; Reset stack
  348.         mov ds,si        ; Reset data segment
  349.         pop dword [fdctab]    ; Restore FDC table
  350. .patch:        mov si,bailmsg
  351.         call writestr        ; Returns with AL = 0
  352.         cbw            ; AH <- 0
  353.         int 16h            ; Wait for keypress
  354.         int 19h            ; And try once more to boot...
  355. .norge:        jmp short .norge    ; If int 19h returned; this is the end
  356.  
  357. ;
  358. ;
  359. ; writestr: write a null-terminated string to the console
  360. ;        This assumes we're on page 0.  This is only used for early
  361. ;           messages, so it should be OK.
  362. ;
  363. writestr:
  364. .loop:        lodsb
  365.         and al,al
  366.                 jz .return
  367.         mov ah,0Eh        ; Write to screen as TTY
  368.         mov bx,0007h        ; Attribute
  369.         int 10h
  370.         jmp short .loop
  371. .return:    ret
  372.  
  373. ;
  374. ; xint13: wrapper for int 13h which will retry 6 times and then die,
  375. ;      AND save all registers except BP
  376. ;
  377. xint13:
  378. .again:
  379.                 mov bp,retry_count
  380. .loop:          pushad
  381.                 int 13h
  382.                 popad
  383.                 jnc writestr.return
  384.                 dec bp
  385.                 jnz .loop
  386. .disk_error:
  387.         jmp strict near kaboom    ; Patched
  388.  
  389.  
  390. ;
  391. ; getonesec: get one disk sector
  392. ;
  393. getonesec:
  394.         mov bp,1        ; One sector
  395.         ; Fall through
  396.  
  397. ;
  398. ; getlinsec: load a sequence of BP floppy sector given by the linear sector
  399. ;         number in EAX into the buffer at ES:BX.  We try to optimize
  400. ;         by loading up to a whole track at a time, but the user
  401. ;         is responsible for not crossing a 64K boundary.
  402. ;         (Yes, BP is weird for a count, but it was available...)
  403. ;
  404. ;         On return, BX points to the first byte after the transferred
  405. ;         block.
  406. ;
  407. ;            This routine assumes CS == DS, and trashes most registers.
  408. ;
  409. ; Stylistic note: use "xchg" instead of "mov" when the source is a register
  410. ; that is dead from that point; this saves space.  However, please keep
  411. ; the order to dst,src to keep things sane.
  412. ;
  413. getlinsec:
  414.         add eax,[bsHidden]        ; Add partition offset
  415. .jmp:        jmp strict short getlinsec_cbios    ; This is patched
  416.  
  417. ;
  418. ; getlinsec_ebios:
  419. ;
  420. ; getlinsec implementation for EBIOS (EDD)
  421. ;
  422. getlinsec_ebios:
  423.                 mov si,dapa                     ; Load up the DAPA
  424.                 mov [si+4],bx
  425.                 mov [si+6],es
  426.                 mov [si+8],eax
  427. .loop:
  428.                 push bp                         ; Sectors left
  429.         call maxtrans            ; Enforce maximum transfer size
  430. .bp_ok:
  431.                 mov [si+2],bp
  432.                 mov dl,[DriveNumber]
  433.                 mov ah,42h                      ; Extended Read
  434.                 call xint13
  435.                 pop bp
  436.                 movzx eax,word [si+2]           ; Sectors we read
  437.                 add [si+8],eax                  ; Advance sector pointer
  438.                 sub bp,ax                       ; Sectors left
  439.                 shl ax,9                        ; 512-byte sectors
  440.                 add [si+4],ax                   ; Advance buffer pointer
  441.                 and bp,bp
  442.                 jnz .loop
  443.                 mov eax,[si+8]                  ; Next sector
  444.                 mov bx,[si+4]                   ; Buffer pointer
  445.                 ret
  446.  
  447. ;
  448. ; getlinsec_cbios:
  449. ;
  450. ; getlinsec implementation for legacy CBIOS
  451. ;
  452. getlinsec_cbios:
  453. .loop:
  454.         push eax
  455.         push bp
  456.         push bx
  457.  
  458.         movzx esi,word [bsSecPerTrack]
  459.         movzx edi,word [bsHeads]
  460.         ;
  461.         ; Dividing by sectors to get (track,sector): we may have
  462.         ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
  463.         ;
  464.         xor edx,edx        ; Zero-extend LBA to 64 bits
  465.         div esi
  466.         xor cx,cx
  467.         xchg cx,dx        ; CX <- sector index (0-based)
  468.                     ; EDX <- 0
  469.         ; eax = track #
  470.         div edi            ; Convert track to head/cyl
  471.         ;
  472.         ; Now we have AX = cyl, DX = head, CX = sector (0-based),
  473.         ; BP = sectors to transfer, SI = bsSecPerTrack,
  474.         ; ES:BX = data target
  475.         ;
  476.  
  477.         call maxtrans            ; Enforce maximum transfer size
  478.  
  479.         ; Must not cross track boundaries, so BP <= SI-CX
  480.         sub si,cx
  481.         cmp bp,si
  482.         jna .bp_ok
  483.         mov bp,si
  484. .bp_ok:    
  485.  
  486.         shl ah,6        ; Because IBM was STOOPID
  487.                     ; and thought 8 bits were enough
  488.                     ; then thought 10 bits were enough...
  489.         inc cx            ; Sector numbers are 1-based, sigh
  490.         or cl,ah
  491.         mov ch,al
  492.         mov dh,dl
  493.         mov dl,[DriveNumber]
  494.         xchg ax,bp        ; Sector to transfer count
  495.         mov ah,02h        ; Read sectors
  496.         call xint13
  497.         movzx ecx,al
  498.         shl ax,9        ; Convert sectors in AL to bytes in AX
  499.         pop bx
  500.         add bx,ax
  501.         pop bp
  502.         pop eax
  503.         add eax,ecx
  504.         sub bp,cx
  505.         jnz .loop
  506.         ret
  507.  
  508. ;
  509. ; Truncate BP to MaxTransfer
  510. ;
  511. maxtrans:
  512.         cmp bp,[MaxTransfer]
  513.         jna .ok
  514.         mov bp,[MaxTransfer]
  515. .ok:        ret
  516.  
  517. ;
  518. ; Error message on failure
  519. ;
  520. bailmsg:    db 'Boot failed', 0Dh, 0Ah, 0
  521.  
  522. ;
  523. ; EBIOS disk address packet
  524. ;
  525.         align 4, db 0
  526. dapa:
  527.                 dw 16                           ; Packet size
  528. .count:         dw 0                            ; Block count
  529. .off:           dw 0                            ; Offset of buffer
  530. .seg:           dw 0                            ; Segment of buffer
  531. .lba:           dd 0                            ; LBA (LSW)
  532.                 dd 0                            ; LBA (MSW)
  533.  
  534.  
  535. %if 1
  536. bs_checkpt_off    equ ($-$$)
  537. %ifndef DEPEND
  538. %if bs_checkpt_off > 1F8h
  539. %error "Boot sector overflow"
  540. %endif
  541. %endif
  542.  
  543.         zb 1F8h-($-$$)
  544. %endif
  545. FirstSector    dd 0xDEADBEEF            ; Location of sector 1
  546. MaxTransfer    dw 0x007F            ; Max transfer size
  547. bootsignature    dw 0AA55h
  548.  
  549. ;
  550. ; ===========================================================================
  551. ;  End of boot sector
  552. ; ===========================================================================
  553. ;  Start of LDLINUX.SYS
  554. ; ===========================================================================
  555.  
  556. ldlinux_sys:
  557.  
  558. syslinux_banner    db 0Dh, 0Ah
  559.         db 'EXTLINUX '
  560.         db version_str, ' ', date, ' ', 0
  561.         db 0Dh, 0Ah, 1Ah    ; EOF if we "type" this in DOS
  562.  
  563.         align 8, db 0
  564. ldlinux_magic    dd LDLINUX_MAGIC
  565.         dd HEXDATE
  566.  
  567. ;
  568. ; This area is patched by the installer.  It is found by looking for
  569. ; LDLINUX_MAGIC, plus 8 bytes.
  570. ;
  571. patch_area:
  572. LDLDwords    dw 0        ; Total dwords starting at ldlinux_sys
  573. LDLSectors    dw 0        ; Number of sectors - (bootsec+this sec)
  574. CheckSum    dd 0        ; Checksum starting at ldlinux_sys
  575.                 ; value = LDLINUX_MAGIC - [sum of dwords]
  576. CurrentDir    dd 2        ; "Current" directory inode number
  577.  
  578. ; Space for up to 64 sectors, the theoretical maximum
  579. SectorPtrs    times 64 dd 0
  580.  
  581. ldlinux_ent:
  582. ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
  583. ; instead of 0000:7C00 and the like.  We don't want to add anything
  584. ; more to the boot sector, so it is written to not assume a fixed
  585. ; value in CS, but we don't want to deal with that anymore from now
  586. ; on.
  587. ;
  588.         jmp 0:.next
  589. .next:
  590.  
  591. ;
  592. ; Tell the user we got this far
  593. ;
  594.         mov si,syslinux_banner
  595.         call writestr
  596.  
  597. ;
  598. ; Patch disk error handling
  599. ;
  600.         mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3)
  601.  
  602. ;
  603. ; Now we read the rest of LDLINUX.SYS.    Don't bother loading the first
  604. ; sector again, though.
  605. ;
  606. load_rest:
  607.         mov si,SectorPtrs
  608.         mov bx,7C00h+2*SECTOR_SIZE    ; Where we start loading
  609.         mov cx,[LDLSectors]
  610.  
  611. .get_chunk:
  612.         jcxz .done
  613.         xor bp,bp
  614.         lodsd                ; First sector of this chunk
  615.  
  616.         mov edx,eax
  617.  
  618. .make_chunk:
  619.         inc bp
  620.         dec cx
  621.         jz .chunk_ready
  622.         inc edx                ; Next linear sector
  623.         cmp [esi],edx            ; Does it match
  624.         jnz .chunk_ready        ; If not, this is it
  625.         add esi,4            ; If so, add sector to chunk
  626.         jmp short .make_chunk
  627.  
  628. .chunk_ready:
  629.         call getlinsecsr
  630.         shl bp,SECTOR_SHIFT
  631.         add bx,bp
  632.         jmp .get_chunk
  633.  
  634. .done:
  635.  
  636. ;
  637. ; All loaded up, verify that we got what we needed.
  638. ; Note: the checksum field is embedded in the checksum region, so
  639. ; by the time we get to the end it should all cancel out.
  640. ;
  641. verify_checksum:
  642.         mov si,ldlinux_sys
  643.         mov cx,[LDLDwords]
  644.         mov edx,-LDLINUX_MAGIC
  645. .checksum:
  646.         lodsd
  647.         add edx,eax
  648.         loop .checksum
  649.  
  650.         and edx,edx            ; Should be zero
  651.         jz all_read            ; We're cool, go for it!
  652.  
  653. ;
  654. ; Uh-oh, something went bad...
  655. ;
  656.         mov si,checksumerr_msg
  657.         call writestr
  658.         jmp kaboom
  659.  
  660. ;
  661. ; -----------------------------------------------------------------------------
  662. ; Subroutines that have to be in the first sector
  663. ; -----------------------------------------------------------------------------
  664.  
  665. ;
  666. ; getlinsecsr: save registers, call getlinsec, restore registers
  667. ;
  668. getlinsecsr:    pushad
  669.         call getlinsec
  670.         popad
  671.         ret
  672.  
  673. ;
  674. ; This routine captures disk errors, and tries to decide if it is
  675. ; time to reduce the transfer size.
  676. ;
  677. do_disk_error:
  678.         cmp ah,42h
  679.         je .ebios
  680.         shr al,1        ; Try reducing the transfer size
  681.         mov [MaxTransfer],al    
  682.         jz kaboom        ; If we can't, we're dead...
  683.         jmp xint13        ; Try again
  684. .ebios:
  685.         push ax
  686.         mov ax,[si+2]
  687.         shr ax,1
  688.         mov [MaxTransfer],ax
  689.         mov [si+2],ax
  690.         pop ax
  691.         jmp xint13
  692.  
  693. ;
  694. ; Checksum error message
  695. ;
  696. checksumerr_msg    db 'Load error - ', 0    ; Boot failed appended
  697.  
  698. ;
  699. ; Debug routine
  700. ;
  701. %ifdef debug
  702. safedumpregs:
  703.         cmp word [Debug_Magic],0D00Dh
  704.         jnz nc_return
  705.         jmp dumpregs
  706. %endif
  707.  
  708. rl_checkpt    equ $                ; Must be <= 8000h
  709.  
  710. rl_checkpt_off    equ ($-$$)
  711. %if 0 ; ndef DEPEND
  712. %if rl_checkpt_off > 400h
  713. %error "Sector 1 overflow"
  714. %endif
  715. %endif
  716.  
  717. ; ----------------------------------------------------------------------------
  718. ;  End of code and data that have to be in the first sector
  719. ; ----------------------------------------------------------------------------
  720.  
  721. all_read:
  722. ;
  723. ; Let the user (and programmer!) know we got this far.  This used to be
  724. ; in Sector 1, but makes a lot more sense here.
  725. ;
  726.         mov si,copyright_str
  727.         call writestr
  728.  
  729. ;
  730. ; Insane hack to expand the DOS superblock to dwords
  731. ;
  732. expand_super:
  733.         xor eax,eax
  734.         mov si,superblock
  735.         mov di,SuperInfo
  736.         mov cx,superinfo_size
  737. .loop:
  738.         lodsw
  739.         dec si
  740.         stosd                ; Store expanded word
  741.         xor ah,ah
  742.         stosd                ; Store expanded byte
  743.         loop .loop
  744.  
  745. ;
  746. ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
  747. ;
  748.         mov bx,SuperBlock
  749.         mov eax,1024 >> SECTOR_SHIFT
  750.         mov bp,ax
  751.         call getlinsec
  752.  
  753. ;
  754. ; Compute some values...
  755. ;
  756.         xor edx,edx
  757.         inc edx
  758.  
  759.         ; s_log_block_size = log2(blocksize) - 10
  760.         mov cl,[SuperBlock+s_log_block_size]
  761.         add cl,10
  762.         mov [ClustByteShift],cl
  763.         mov eax,edx
  764.         shl eax,cl
  765.         mov [ClustSize],eax
  766.  
  767.         sub cl,SECTOR_SHIFT
  768.         mov [ClustShift],cl
  769.         shr eax,SECTOR_SHIFT
  770.         mov [SecPerClust],eax
  771.         dec eax
  772.         mov [ClustMask],eax
  773.  
  774.         add cl,SECTOR_SHIFT-2        ; 4 bytes/pointer
  775.         shl edx,cl
  776.         mov [PtrsPerBlock1],edx
  777.         shl edx,cl
  778.         mov [PtrsPerBlock2],edx
  779.  
  780. ;
  781. ; Common initialization code
  782. ;
  783. %include "init.inc"
  784. %include "cpuinit.inc"
  785.  
  786. ;
  787. ; Initialize the metadata cache
  788. ;
  789.         call initcache
  790.  
  791. ;
  792. ; Now, everything is "up and running"... patch kaboom for more
  793. ; verbosity and using the full screen system
  794. ;
  795.         ; E9 = JMP NEAR
  796.         mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
  797.  
  798. ;
  799. ; Now we're all set to start with our *real* business.    First load the
  800. ; configuration file (if any) and parse it.
  801. ;
  802. ; In previous versions I avoided using 32-bit registers because of a
  803. ; rumour some BIOSes clobbered the upper half of 32-bit registers at
  804. ; random.  I figure, though, that if there are any of those still left
  805. ; they probably won't be trying to install Linux on them...
  806. ;
  807. ; The code is still ripe with 16-bitisms, though.  Not worth the hassle
  808. ; to take'm out.  In fact, we may want to put them back if we're going
  809. ; to boot ELKS at some point.
  810. ;
  811.  
  812. ;
  813. ; Load configuration file
  814. ;
  815. load_config:
  816.         mov di,ConfigName
  817.         call open
  818.         jz no_config_file
  819.  
  820. ;
  821. ; Now we have the config file open.  Parse the config file and
  822. ; run the user interface.
  823. ;
  824. %include "ui.inc"
  825.  
  826. ;
  827. ; Linux kernel loading code is common.
  828. ;
  829. %include "runkernel.inc"
  830.  
  831. ;
  832. ; COMBOOT-loading code
  833. ;
  834. %include "comboot.inc"
  835. %include "com32.inc"
  836. %include "cmdline.inc"
  837.  
  838. ;
  839. ; Boot sector loading code
  840. ;
  841. %include "bootsect.inc"
  842.  
  843. ;
  844. ; abort_check: let the user abort with <ESC> or <Ctrl-C>
  845. ;
  846. abort_check:
  847.         call pollchar
  848.         jz ac_ret1
  849.         pusha
  850.         call getchar
  851.         cmp al,27            ; <ESC>
  852.         je ac_kill
  853.         cmp al,3            ; <Ctrl-C>
  854.         jne ac_ret2
  855. ac_kill:    mov si,aborted_msg
  856.  
  857. ;
  858. ; abort_load: Called by various routines which wants to print a fatal
  859. ;             error message and return to the command prompt.  Since this
  860. ;             may happen at just about any stage of the boot process, assume
  861. ;             our state is messed up, and just reset the segment registers
  862. ;             and the stack forcibly.
  863. ;
  864. ;             SI    = offset (in _text) of error message to print
  865. ;
  866. abort_load:
  867.                 mov ax,cs                       ; Restore CS = DS = ES
  868.                 mov ds,ax
  869.                 mov es,ax
  870.                 cli
  871.                 mov sp,StackBuf-2*3            ; Reset stack
  872.                 mov ss,ax                       ; Just in case...
  873.                 sti
  874.                 call cwritestr                  ; Expects SI -> error msg
  875. al_ok:          jmp enter_command               ; Return to command prompt
  876. ;
  877. ; End of abort_check
  878. ;
  879. ac_ret2:    popa
  880. ac_ret1:    ret
  881.  
  882. ;
  883. ; allocate_file: Allocate a file structure
  884. ;
  885. ;        If successful:
  886. ;          ZF set
  887. ;          BX = file pointer
  888. ;        In unsuccessful:
  889. ;          ZF clear
  890. ;
  891. allocate_file:
  892.         TRACER 'a'
  893.         push cx
  894.         mov bx,Files
  895.         mov cx,MAX_OPEN
  896. .check:        cmp dword [bx], byte 0
  897.         je .found
  898.         add bx,open_file_t_size        ; ZF = 0
  899.         loop .check
  900.         ; ZF = 0 if we fell out of the loop
  901. .found:        pop cx
  902.         ret
  903. ;
  904. ; open_inode:
  905. ;         Open a file indicated by an inode number in EAX
  906. ;
  907. ;         NOTE: This file considers finding a zero-length file an
  908. ;         error.  This is so we don't have to deal with that special
  909. ;         case elsewhere in the program (most loops have the test
  910. ;         at the end).
  911. ;
  912. ;         If successful:
  913. ;        ZF clear
  914. ;        SI        = file pointer
  915. ;        DX:AX = EAX = file length in bytes
  916. ;         If unsuccessful
  917. ;        ZF set
  918. ;
  919. open_inode.allocate_failure:
  920.         xor eax,eax
  921.         ret
  922.  
  923. open_inode:
  924.         call allocate_file
  925.         jnz .allocate_failure
  926.  
  927.         push gs
  928.         ; First, get the appropriate inode group and index
  929.         dec eax                ; There is no inode 0
  930.         xor edx,edx
  931.         mov [bx+file_sector],edx
  932.         div dword [SuperBlock+s_inodes_per_group]
  933.         ; EAX = inode group; EDX = inode within group
  934.         push edx
  935.  
  936.         ; Now, we need the block group descriptor.
  937.         ; To get that, we first need the relevant descriptor block.
  938.                 
  939.         shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
  940.         xor edx,edx
  941.         div dword [ClustSize]
  942.         ; eax = block #, edx = offset in block
  943.         add eax,dword [SuperBlock+s_first_data_block]
  944.         inc eax                ; s_first_data_block+1
  945.         mov cl,[ClustShift]
  946.         shl eax,cl
  947.         call getcachesector        ; Get the group descriptor
  948.         add si,dx
  949.         mov esi,[gs:si+bg_inode_table]    ; Get inode table block #
  950.         pop eax                ; Get inode within group
  951.         movzx edx, word [SuperBlock+s_inode_size]
  952.         mul edx
  953.         ; edx:eax = byte offset in inode table
  954.         div dword [ClustSize]
  955.         ; eax = block # versus inode table, edx = offset in block
  956.         add eax,esi
  957.         shl eax,cl            ; Turn into sector
  958.         push dx
  959.         shr edx,SECTOR_SHIFT
  960.         add eax,edx
  961.         mov [bx+file_in_sec],eax
  962.         pop dx
  963.         and dx,SECTOR_SIZE-1
  964.         mov [bx+file_in_off],dx
  965.  
  966.         call getcachesector
  967.         add si,dx
  968.         mov ax,[gs:si+i_mode]
  969.         mov [bx+file_mode],ax
  970.         mov eax,[gs:si+i_size]
  971.         push eax
  972.         add eax,SECTOR_SIZE-1
  973.         shr eax,SECTOR_SHIFT
  974.         mov [bx+file_left],eax
  975.         pop eax
  976.         mov si,bx
  977.         mov edx,eax
  978.         shr edx,16            ; 16-bitism, sigh
  979.         and eax,eax            ; ZF clear unless zero-length file
  980.         pop gs
  981.         ret
  982.  
  983. ;
  984. ; close:
  985. ;         Deallocates a file structure (pointer in SI)
  986. ;         Assumes CS == DS.
  987. ;
  988. close:
  989.         mov dword [si],0        ; First dword == file_left
  990.         ret
  991.  
  992. ;
  993. ; searchdir:
  994. ;         Search the root directory for a pre-mangled filename in DS:DI.
  995. ;
  996. ;         NOTE: This file considers finding a zero-length file an
  997. ;         error.  This is so we don't have to deal with that special
  998. ;         case elsewhere in the program (most loops have the test
  999. ;         at the end).
  1000. ;
  1001. ;         If successful:
  1002. ;        ZF clear
  1003. ;        SI        = file pointer
  1004. ;        DX:AX = EAX = file length in bytes
  1005. ;         If unsuccessful
  1006. ;        ZF set
  1007. ;
  1008. ;         Assumes CS == DS == ES; *** IS THIS CORRECT ***?
  1009. ;
  1010. searchdir:
  1011.         push bx
  1012.         push cx
  1013.         push di
  1014.         mov eax,[CurrentDir]
  1015. .leadingslash:
  1016.         cmp byte [di],'/'    ; Absolute filename?
  1017.         jne .searchloop
  1018.         mov eax,EXT2_ROOT_INO
  1019.         inc di            ; Skip slash
  1020.  
  1021. .searchloop:
  1022.         ; At this point, EAX contains the directory inode,
  1023.         ; and DS:DI contains a pathname tail.
  1024.         call open_inode
  1025.  
  1026. .readdir:
  1027.         mov bx,trackbuf
  1028.         push bx
  1029.         mov cx,[SecPerClust]
  1030.         call getfssec
  1031.         pop bx
  1032.         pushf            ; Save EOF flag
  1033. .getent:
  1034.         cmp dword [bx+d_inode],0
  1035.         je .endblock
  1036.         
  1037.         push di
  1038.         movzx cx,byte [bx+d_name_len]
  1039.         lea si,[bx+d_name]
  1040.         repe cmpsb
  1041.         je .maybe
  1042. .nope:
  1043.         pop di
  1044.  
  1045.         add bx,[bx+d_rec_len]
  1046.         jmp .getent
  1047.  
  1048. .endblock:
  1049.         popf
  1050.         jnc .readdir        ; There is more
  1051. .failure:
  1052.         xor eax,eax
  1053.         jmp .done
  1054. .maybe:
  1055.         mov eax,[bx+d_inode]
  1056.         
  1057.         cmp byte [di],0
  1058.         je .finish        ; It's a real file; done
  1059.         cmp byte [di],'/'
  1060.         jne .nope        ; False alarm
  1061.         
  1062.         ; It's a match, but it's a directory.
  1063.         ; Repeat operation.
  1064.         call close
  1065.         pop si            ; Adjust stack (di)
  1066.         pop si            ; Adjust stack (flags)
  1067.         inc di            ; Skip slash
  1068.         jmp .searchloop
  1069.         
  1070.  
  1071. .finish:    ; We found it; now we need to open the file
  1072.         call close        ; Close directory
  1073.         pop si            ; Adjust stack (di)
  1074.         pop si            ; Adjust stack (flags)
  1075.         call open_inode
  1076. .done:
  1077.         pop di
  1078.         pop cx
  1079.         pop bx
  1080.         ret
  1081.  
  1082. ;
  1083. ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
  1084. ;           to by ES:DI; ends on encountering any whitespace.
  1085. ;
  1086. ;           This verifies that a filename is < FILENAME_MAX characters,
  1087. ;           doesn't contain whitespace, zero-pads the output buffer,
  1088. ;           and removes redundant slashes,
  1089. ;           so "repe cmpsb" can do a compare, and the
  1090. ;           path-searching routine gets a bit of an easier job.
  1091. ;
  1092. ;           FIX: we may want to support \-escapes here (and this would
  1093. ;           be the place.)
  1094. ;           
  1095. mangle_name:
  1096.         push bx
  1097.         xor ax,ax
  1098.         mov cx,FILENAME_MAX-1
  1099.         mov bx,di
  1100.  
  1101. .mn_loop:
  1102.         lodsb
  1103.         cmp al,' '            ; If control or space, end
  1104.         jna .mn_end
  1105.         cmp al,ah            ; Repeated slash?
  1106.         je .mn_skip
  1107.         xor ah,ah
  1108.         cmp al,'/'
  1109.         jne .mn_ok
  1110.         mov ah,al
  1111. .mn_ok        stosb
  1112. .mn_skip:    loop .mn_loop
  1113. .mn_end:
  1114.         cmp bx,di            ; At the beginning of the buffer?
  1115.         jbe .mn_zero
  1116.         cmp byte [di-1],'/'        ; Terminal slash?
  1117.         jne .mn_zero
  1118. .mn_kill:    dec di                ; If so, remove it
  1119.         inc cx
  1120.         jmp short .mn_end
  1121. .mn_zero:
  1122.         inc cx                ; At least one null byte
  1123.         xor ax,ax            ; Zero-fill name
  1124.         rep stosb
  1125.         pop bx
  1126.         ret                ; Done
  1127.  
  1128. ;
  1129. ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
  1130. ;                filename to the conventional representation.  This is needed
  1131. ;                for the BOOT_IMAGE= parameter for the kernel.
  1132. ;                NOTE: A 13-byte buffer is mandatory, even if the string is
  1133. ;                known to be shorter.
  1134. ;
  1135. ;                DS:SI -> input mangled file name
  1136. ;                ES:DI -> output buffer
  1137. ;
  1138. ;                On return, DI points to the first byte after the output name,
  1139. ;                which is set to a null byte.
  1140. ;
  1141. unmangle_name:    call strcpy
  1142.         dec di                ; Point to final null byte
  1143.         ret
  1144.  
  1145. ;
  1146. ; writechr:    Write a single character in AL to the console without
  1147. ;        mangling any registers; handle video pages correctly.
  1148. ;
  1149. writechr:
  1150.         call write_serial    ; write to serial port if needed
  1151.         pushfd
  1152.         test byte [cs:DisplayCon],01h
  1153.         jz .nothing
  1154.         pushad
  1155.         mov ah,0Eh
  1156.         mov bl,07h        ; attribute
  1157.         mov bh,[cs:BIOS_page]    ; current page
  1158.         int 10h
  1159.         popad
  1160. .nothing:
  1161.         popfd
  1162.         ret
  1163.  
  1164. ;
  1165. ;
  1166. ; kaboom2: once everything is loaded, replace the part of kaboom
  1167. ;       starting with "kaboom.patch" with this part
  1168.  
  1169. kaboom2:
  1170.         mov si,err_bootfailed
  1171.         call cwritestr
  1172.         call getchar
  1173.         call vgaclearmode
  1174.         int 19h            ; And try once more to boot...
  1175. .norge:        jmp short .norge    ; If int 19h returned; this is the end
  1176.  
  1177.  
  1178. ;
  1179. ; linsector:    Convert a linear sector index in a file to a linear sector number
  1180. ;    EAX    -> linear sector number
  1181. ;    DS:SI    -> open_file_t
  1182. ;
  1183. ;        Returns next sector number in EAX; CF on EOF (not an error!)
  1184. ;
  1185. linsector:
  1186.         push gs
  1187.         push ebx
  1188.         push esi
  1189.         push edi
  1190.         push ecx
  1191.         push edx
  1192.         push ebp
  1193.  
  1194.         push eax        ; Save sector index
  1195.         mov cl,[ClustShift]
  1196.         shr eax,cl        ; Convert to block number
  1197.         push eax
  1198.         mov eax,[si+file_in_sec]
  1199.         mov bx,si
  1200.         call getcachesector    ; Get inode
  1201.         add si,[bx+file_in_off]    ; Get *our* inode
  1202.         pop eax
  1203.         lea ebx,[i_block+4*eax]
  1204.         cmp eax,EXT2_NDIR_BLOCKS
  1205.         jb .direct
  1206.         mov ebx,i_block+4*EXT2_IND_BLOCK
  1207.         sub eax,EXT2_NDIR_BLOCKS
  1208.         mov ebp,[PtrsPerBlock1]
  1209.         cmp eax,ebp
  1210.         jb .ind1
  1211.         mov ebx,i_block+4*EXT2_DIND_BLOCK
  1212.         sub eax,ebp
  1213.         mov ebp,[PtrsPerBlock2]
  1214.         cmp eax,ebp
  1215.         jb .ind2
  1216.         mov ebx,i_block+4*EXT2_TIND_BLOCK
  1217.         sub eax,ebp
  1218.  
  1219. .ind3:
  1220.         ; Triple indirect; eax contains the block no
  1221.         ; with respect to the start of the tind area;
  1222.         ; ebx contains the pointer to the tind block.
  1223.         xor edx,edx
  1224.         div dword [PtrsPerBlock2]
  1225.         ; EAX = which dind block, EDX = pointer within dind block
  1226.         push ax
  1227.         shr eax,SECTOR_SHIFT-2
  1228.         mov ebp,[gs:si+bx]
  1229.         shl ebp,cl
  1230.         add eax,ebp
  1231.         call getcachesector
  1232.         pop bx
  1233.         and bx,(SECTOR_SIZE >> 2)-1
  1234.         shl bx,2
  1235.         mov eax,edx        ; The ind2 code wants the remainder...
  1236.  
  1237. .ind2:
  1238.         ; Double indirect; eax contains the block no
  1239.         ; with respect to the start of the dind area;
  1240.         ; ebx contains the pointer to the dind block.
  1241.         xor edx,edx
  1242.         div dword [PtrsPerBlock1]
  1243.         ; EAX = which ind block, EDX = pointer within ind block
  1244.         push ax
  1245.         shr eax,SECTOR_SHIFT-2
  1246.         mov ebp,[gs:si+bx]
  1247.         shl ebp,cl
  1248.         add eax,ebp
  1249.         call getcachesector
  1250.         pop bx
  1251.         and bx,(SECTOR_SIZE >> 2)-1
  1252.         shl bx,2
  1253.         mov eax,edx        ; The int1 code wants the remainder...
  1254.  
  1255. .ind1:
  1256.         ; Single indirect; eax contains the block no
  1257.         ; with respect to the start of the ind area;
  1258.         ; ebx contains the pointer to the ind block.
  1259.         push ax
  1260.         shr eax,SECTOR_SHIFT-2
  1261.         mov ebp,[gs:si+bx]
  1262.         shl ebp,cl
  1263.         add eax,ebp
  1264.         call getcachesector
  1265.         pop bx
  1266.         and bx,(SECTOR_SIZE >> 2)-1
  1267.         shl bx,2
  1268.  
  1269. .direct:
  1270.         mov ebx,[gs:bx+si]    ; Get the pointer
  1271.  
  1272.         pop eax            ; Get the sector index again
  1273.         shl ebx,cl        ; Convert block number to sector
  1274.         and eax,[ClustMask]    ; Add offset within block
  1275.         add eax,ebx
  1276.  
  1277.         pop ebp
  1278.         pop edx
  1279.         pop ecx
  1280.         pop edi
  1281.         pop esi
  1282.         pop ebx
  1283.         pop gs
  1284.         ret
  1285.  
  1286. ;
  1287. ; getfssec: Get multiple sectors from a file
  1288. ;
  1289. ;    Same as above, except SI is a pointer to a open_file_t
  1290. ;
  1291. ;    ES:BX    -> Buffer
  1292. ;    DS:SI    -> Pointer to open_file_t
  1293. ;    CX    -> Sector count (0FFFFh = until end of file)
  1294. ;                  Must not exceed the ES segment
  1295. ;    Returns CF=1 on EOF (not necessarily error)
  1296. ;    All arguments are advanced to reflect data read.
  1297. ;
  1298. getfssec:
  1299.         push ebp
  1300.         push eax
  1301.         push edx
  1302.         push edi
  1303. .getfragment:
  1304.         mov eax,[si+file_sector]    ; Current start index
  1305.         mov edi,eax
  1306.         call linsector
  1307.         push eax            ; Fragment start sector
  1308.         mov edx,eax
  1309.         xor ebp,ebp            ; Fragment sector count
  1310. .getseccnt:
  1311.         inc bp
  1312.         dec cx
  1313.         jz .do_read
  1314.         xor eax,eax
  1315.         mov ax,es
  1316.         shl ax,4
  1317.         add ax,bx            ; Now DI = how far into 64K block we are
  1318.         not ax                ; Bytes left in 64K block
  1319.         inc eax
  1320.         shr eax,SECTOR_SHIFT        ; Sectors left in 64K block
  1321.         cmp bp,ax
  1322.         jnb .do_read            ; Unless there is at least 1 more sector room...
  1323.         inc edi                ; Sector index
  1324.         inc edx                ; Linearly next sector
  1325.         mov eax,edi
  1326.         call linsector
  1327.         ; jc .do_read
  1328.         cmp edx,eax
  1329.         je .getseccnt
  1330. .do_read:
  1331.         pop eax                ; Linear start sector
  1332.         call getlinsecsr
  1333.         push bp
  1334.         shl bp,9
  1335.         add bx,bp            ; Adjust buffer pointer
  1336.         pop bp
  1337.         add [si+file_sector],ebp    ; Next sector index
  1338.         sub [si],ebp            ; Sectors consumed
  1339.         jz .done
  1340.         jcxz .done
  1341.         jmp .getfragment
  1342. .done:
  1343.         cmp dword [si],1        ; Did we run out of file?
  1344.         ; CF set if [SI] < 1, i.e. == 0
  1345.         pop edi
  1346.         pop edx
  1347.         pop eax
  1348.         pop ebp
  1349.         ret
  1350.  
  1351. ; -----------------------------------------------------------------------------
  1352. ;  Common modules
  1353. ; -----------------------------------------------------------------------------
  1354.  
  1355. %include "getc.inc"        ; getc et al
  1356. %include "conio.inc"        ; Console I/O
  1357. %include "writestr.inc"        ; String output
  1358. %include "parseconfig.inc"    ; High-level config file handling
  1359. %include "parsecmd.inc"        ; Low-level config file handling
  1360. %include "bcopy32.inc"        ; 32-bit bcopy
  1361. %include "loadhigh.inc"        ; Load a file into high memory
  1362. %include "font.inc"        ; VGA font stuff
  1363. %include "graphics.inc"        ; VGA graphics
  1364. %include "highmem.inc"        ; High memory sizing
  1365. %include "strcpy.inc"           ; strcpy()
  1366. %include "cache.inc"
  1367.  
  1368. ; -----------------------------------------------------------------------------
  1369. ;  Begin data section
  1370. ; -----------------------------------------------------------------------------
  1371.  
  1372.         section .data
  1373. copyright_str   db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
  1374.         db CR, LF, 0
  1375. boot_prompt    db 'boot: ', 0
  1376. wipe_char    db BS, ' ', BS, 0
  1377. err_notfound    db 'Could not find kernel image: ',0
  1378. err_notkernel    db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
  1379. err_noram    db 'It appears your computer has less than '
  1380.         asciidec dosram_k
  1381.         db 'K of low ("DOS")'
  1382.         db CR, LF
  1383.         db 'RAM.  Linux needs at least this amount to boot.  If you get'
  1384.         db CR, LF
  1385.         db 'this message in error, hold down the Ctrl key while'
  1386.         db CR, LF
  1387.         db 'booting, and I will take your word for it.', CR, LF, 0
  1388. err_badcfg      db 'Unknown keyword in extlinux.conf.', CR, LF, 0
  1389. err_noparm      db 'Missing parameter in extlinux.conf.', CR, LF, 0
  1390. err_noinitrd    db CR, LF, 'Could not find ramdisk image: ', 0
  1391. err_nohighmem   db 'Not enough memory to load specified kernel.', CR, LF, 0
  1392. err_highload    db CR, LF, 'Kernel transfer failure.', CR, LF, 0
  1393. err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
  1394.                 db CR, LF, 0
  1395. err_notdos    db ': attempted DOS system call', CR, LF, 0
  1396. err_comlarge    db 'COMBOOT image too large.', CR, LF, 0
  1397. err_bssimage    db 'BSS images not supported.', CR, LF, 0
  1398. err_a20        db CR, LF, 'A20 gate not responding!', CR, LF, 0
  1399. err_bootfailed    db CR, LF, 'Boot failed: please change disks and press '
  1400.         db 'a key to continue.', CR, LF, 0
  1401. ready_msg    db 'Ready.', CR, LF, 0
  1402. crlfloading_msg    db CR, LF
  1403. loading_msg     db 'Loading ', 0
  1404. dotdot_msg      db '.'
  1405. dot_msg         db '.', 0
  1406. aborted_msg    db ' aborted.'            ; Fall through to crlf_msg!
  1407. crlf_msg    db CR, LF
  1408. null_msg    db 0
  1409. crff_msg    db CR, FF, 0
  1410. ConfigName    db 'extlinux.conf',0        ; Unmangled form
  1411.  
  1412. ;
  1413. ; Command line options we'd like to take a look at
  1414. ;
  1415. ; mem= and vga= are handled as normal 32-bit integer values
  1416. initrd_cmd    db 'initrd='
  1417. initrd_cmd_len    equ 7
  1418.  
  1419. ;
  1420. ; Config file keyword table
  1421. ;
  1422. %include "keywords.inc"
  1423.  
  1424. ;
  1425. ; Extensions to search for (in *forward* order).
  1426. ;
  1427.         align 4, db 0
  1428. exten_table:    db '.cbt'        ; COMBOOT (specific)
  1429.         db '.img'        ; Disk image
  1430.         db '.bs', 0        ; Boot sector
  1431.         db '.com'        ; COMBOOT (same as DOS)
  1432.         db '.c32'        ; COM32
  1433. exten_table_end:
  1434.         dd 0, 0            ; Need 8 null bytes here
  1435.  
  1436. ;
  1437. ; Misc initialized (data) variables
  1438. ;
  1439. %ifdef debug                ; This code for debugging only
  1440. debug_magic    dw 0D00Dh        ; Debug code sentinel
  1441. %endif
  1442.  
  1443.         alignb 4, db 0
  1444. BufSafe        dw trackbufsize/SECTOR_SIZE    ; Clusters we can load into trackbuf
  1445. BufSafeSec    dw trackbufsize/SECTOR_SIZE    ; = how many sectors?
  1446. BufSafeBytes    dw trackbufsize        ; = how many bytes?
  1447. EndOfGetCBuf    dw getcbuf+trackbufsize    ; = getcbuf+BufSafeBytes
  1448. %ifndef DEPEND
  1449. %if ( trackbufsize % SECTOR_SIZE ) != 0
  1450. %error trackbufsize must be a multiple of SECTOR_SIZE
  1451. %endif
  1452. %endif
  1453.